package service

import (
	"context"
	"encoding/json"
	"fmt"
	"github.com/wonderivan/logger"
	"net/url"
	"time"
	"ucenter/app/dao"
	"ucenter/app/model"
	"ucenter/app/validator"
	"ucenter/utils"
)

//TODO 主动缓存设计

var userService *UserService

type UserService struct{}

const LoginRedisKey = "%v:%v"

func GetUserService() *UserService {
	if userService == nil {
		userService = new(UserService)
	}
	return userService
}

/**
短信登录
*/
func (us *UserService) SmsLogin(phone string, code string) (user *model.User, resKey string) {
	//code校验
	res, resKey := us.ValidateSmsCode(phone, code)
	if !res {
		return nil, resKey
	}
	//查询用户信息
	userExist, err := dao.GetMysql().Where("phone=?", phone).Get(user)
	if err != nil {
		return nil, "DB_ERROR"
	}
	if !userExist {
		return nil, "NO_REGISTER"
	}
	//返回用户信息
	return user, ""
}

/**
验证短信验证码
*/
func (us *UserService) ValidateSmsCode(phone string, code string) (res bool, resKey string) {
	userSmsCode := new(model.UserSmsCode)
	exist, err := dao.GetMysql().Where("phone=?", phone).OrderBy("id desc").Limit(1).Get(userSmsCode)
	if err != nil {
		return false, "DB_ERROR"
	}
	if !exist {
		return false, "CODE_WRONG"
	}
	if userSmsCode.Created < (utils.GetIDTime() - 300) {
		return false, "CODE_WRONG"
	}
	if userSmsCode.Code != code {
		return false, "CODE_WRONG"
	}
	return true, ""
}

/**
用户登录
*/
func (us *UserService) Login(userArgs validator.LoginValidator) (user *model.User, resKey string) {
	//查询是否有注册账号
	if userArgs.Phone == "" {
		userInfo := new(model.User)
		session := dao.GetMysql().NewSession()
		if userArgs.LoginType == validator.GOOGLE {
			session.Where("google_id=?", userArgs.GoogleId)
		} else if userArgs.LoginType == validator.FACEBOOK {
			session.Where("facebook_id=?", userArgs.FacebookId)
		} else {
			return nil, "DB_ERROR"
		}
		userExist, err := session.Get(userInfo)
		if err != nil {
			return nil, "DB_ERROR"
		}
		if !userExist || userInfo.Phone == "" {
			return nil, "NEED_BIND_PHONE"
		}
		//重新设置token
		newToken := utils.GenerateToken(userInfo.Phone)
		_, err = dao.GetMysql().Where("id=?", userInfo.Id).Update(&model.User{Token: newToken})
		if err != nil {
			return nil, "DB_ERROR"
		}
		userInfo.Token = newToken
		//设置登录session
		_ = us.SetRedisUserInfo(userInfo)
		return userInfo, ""
	}
	//验证短信验证码
	res, resKey := us.ValidateSmsCode(userArgs.Phone, userArgs.SmsCode)
	if !res {
		return nil, resKey
	}
	//校验facebook,google是否被绑定
	if userArgs.GoogleId != "" {
		googleExist, err := dao.GetMysql().Where("google_id=?", userArgs.GoogleId).Get(&model.User{})
		if err != nil {
			return nil, "DB_ERROR"
		}
		if googleExist {
			return nil, "GOOGLE_BIND_EXIST"
		}
	}
	if userArgs.FacebookId != "" {
		googleExist, err := dao.GetMysql().Where("facebook_id=?", userArgs.FacebookId).Get(&model.User{})
		if err != nil {
			return nil, "DB_ERROR"
		}
		if googleExist {
			return nil, "FACEBOOK_BIND_EXIST"
		}
	}
	//手机号是否注册
	userRegister := new(model.User)
	regExist, err := dao.GetMysql().Where("phone=?", userArgs.Phone).Get(userRegister)
	if err != nil {
		return nil, "DB_ERROR"
	}

	if regExist {
		//是否重复绑
		if userArgs.LoginType == validator.GOOGLE && userRegister.GoogleId != "" {
			return nil, "GOOGLE_BIND_EXIST"
		}
		if userArgs.LoginType == validator.FACEBOOK && userRegister.FacebookId != "" {
			return nil, "FACEBOOK_BIND_EXIST"
		}
		if userArgs.LoginType != validator.PHONE {
			userRegister.Avatar = userArgs.Avatar
			userRegister.NickName = userArgs.NickName
			userRegister.FacebookId = userArgs.FacebookId
			userRegister.GoogleId = userArgs.GoogleId
		}
		userRegister.Token = utils.GenerateToken(userArgs.DeviceId)
		_, err = dao.GetMysql().Where("id=?", userRegister.Id).Update(userRegister)
		if err != nil {
			logger.Error("RegisterUserDbError | err+%v", err)
			return nil, "DB_ERROR"
		}
	} else {
		userRegister.Phone = userArgs.Phone
		userRegister.Avatar = userArgs.Avatar
		if userArgs.NickName == "" {
			userArgs.NickName = fmt.Sprintf("player%s%s", time.Now().Format("20060102"), utils.CreateCaptcha())
		}
		userRegister.NickName = userArgs.NickName
		userRegister.DeviceId = userArgs.DeviceId
		userRegister.FacebookId = userArgs.FacebookId
		userRegister.GoogleId = userArgs.GoogleId
		userRegister.Token = utils.GenerateToken(userArgs.DeviceId)
		_, err = dao.GetMysql().Insert(userRegister)
		if err != nil {
			//logger.Error("RegisterUserDbError | err+%v", err)
			return nil, "DB_ERROR"
		}
		//注册送余额在这写 todo
		GetBalanceService().InitBalance(&model.UserBalance{Uid: userRegister.Id, Score: 5000000})
	}
	_ = us.SetRedisUserInfo(userRegister)
	return userRegister, ""
}

/**
游客登录
*/
func (us *UserService) TouristLogin(userArgs validator.LoginValidator) (user *model.User, resKey string) {
	newRegister := new(model.User)
	exist, err := dao.GetMysql().Where("device_id=?", userArgs.DeviceId).Get(newRegister)
	if err != nil {
		logger.Error("UserService_TouristLogin_DB1 | err+%v", err)
		return nil, "DB_ERROR"
	}
	if !exist {
		newRegister.DeviceId = userArgs.DeviceId
		newRegister.NickName = fmt.Sprintf("player%s%s", time.Now().Format("20060102"), utils.CreateCaptcha())
		newRegister.Token = utils.GenerateToken(userArgs.DeviceId)
		_, err = dao.GetMysql().Insert(newRegister)
		if err != nil {
			logger.Error("UserService_TouristLogin_DB2 | err+%v", err)
			return nil, "DB_ERROR"
		}
		//注册送余额在这写 todo
		GetBalanceService().InitBalance(&model.UserBalance{Uid: newRegister.Id, Score: 5000000})
	}
	_ = us.SetRedisUserInfo(newRegister)
	return newRegister, ""
}

func (us *UserService) TouristBind(bindVal validator.BindValidator) (res bool, resKey string) {
	regUser := new(model.User)
	exist, err := dao.GetMysql().Where("token=?", bindVal.Token).Get(regUser)
	if err != nil {
		logger.Error("UserService_TouristBind_DB1 | err+%v", err)
		return false, "DB_ERROR"
	}
	if !exist {
		return false, "NO_REGISTER"
	}
	logger.Debug("UserService_TouristBind_Info | data=%+v", bindVal)
	if bindVal.Type == validator.PHONE && regUser.Phone == "" {
		//验证短信验证码
		res, resKey := us.ValidateSmsCode(bindVal.Phone, bindVal.SmsCode)
		if !res {
			return false, resKey
		}
		//手机号是否注册
		userRegister := new(model.User)
		regExist, err := dao.GetMysql().Where("phone=?", bindVal.Phone).Get(userRegister)
		if err != nil {
			logger.Error("UserService_TouristBind_DB2 | err+%v", err)
			return false, "DB_ERROR"
		}
		if regExist {
			return false, "PHONE_EXIST"
		}
		_, err = dao.GetMysql().Where("id=?", regUser.Id).Update(&model.User{Phone: bindVal.Phone})
	} else if bindVal.Type == validator.GOOGLE && regUser.GoogleId == "" {
		_, err = dao.GetMysql().Where("id=?", regUser.Id).Update(&model.User{GoogleId: bindVal.GoogleId})
	} else if bindVal.Type == validator.FACEBOOK && regUser.FacebookId == "" {
		_, err = dao.GetMysql().Where("id=?", regUser.Id).Update(&model.User{FacebookId: bindVal.FacebookId})
	}
	if err != nil {
		logger.Error("UserService_TouristBind_DB3 | err=+%v | data=%v", err, bindVal)
		return false, "DB_ERROR"
	}
	return true, ""
}

func (us *UserService) GetUserBaseInfo(uid int64) (resKey string, userInfo *model.User, balanceInfo *model.UserBalance) {
	user := new(model.User)
	userExist, err := dao.GetMysql().Where("id=?", uid).Get(user)
	if err != nil {
		logger.Error("UserService_GetUserBaseInfo_DB_Err | err=+%v | uid=%v", err, uid)
		return "DB_ERROR", nil, nil
	}
	if !userExist {
		logger.Error("UserService_GetUserBaseInfo_Exist | err=+%v | uid=%v", err, uid)
		return "NOT_EXIST", nil, nil
	}
	userBalance := new(model.UserBalance)
	_, err = dao.GetMysql().Where("uid=?", uid).Get(userBalance)
	if err != nil {
		logger.Error("UserService_GetUserBaseInfo_Balance_Err | err=+%v | uid=%v", err, uid)
		return "DB_ERROR", nil, nil
	}
	return "", user, userBalance
}

func (us *UserService) GetSimpleUserInfo(uid interface{}) (resKey string, userInfo *model.User, userList []*model.User) {
	var (
		userExist bool
		err       error
	)
	userInfo = new(model.User)
	switch uid.(type) {
	case int64:
		userExist, err = dao.GetMysql().Where("id=?", uid).Select("id, nick_name,avatar").Get(userInfo)
	case []int64:
		userExist = true
		err = dao.GetMysql().In("id", uid).Select("id, nick_name,avatar").Find(&userList)
	}
	if err != nil {
		logger.Error("UserService_GetUserBaseInfo_DB_Err | err=+%v | uid=%v", err, uid)
		resKey = "DB_ERROR"
		return
	}
	if !userExist {
		logger.Error("UserService_GetUserBaseInfo_Exist | err=+%v | uid=%v", err, uid)
		resKey = "NOT_EXIST"
		return
	}
	return
}

func (us *UserService) GetUserInfoByToken(token string) (userInfo *model.User) {
	uKey := fmt.Sprintf("user_token:%v", token)
	cacheData := dao.RedisGet(uKey)
	user := new(model.User)
	if cacheData != nil {
		err := json.Unmarshal(cacheData.([]byte), user)
		if err != nil {
			return user
		}
	}
	_, err := dao.GetMysql().Where("token=?", token).Get(user)
	if err != nil {
		logger.Error("UserService_GetUserBaseInfo_DB_Err | err=+%v | token=%v", err, token)
	}
	cData, err := json.Marshal(user)
	if err == nil {
		dao.RedisSet(uKey, string(cData))
	}
	return user
}

/**
发送验证码
*/
func (us *UserService) SendLoginCode(phone string) (err error) {
	code := utils.CreateCaptcha()
	code = "123456"
	userSmsCode := new(model.UserSmsCode)
	userSmsCode.Phone = phone
	userSmsCode.Code = code
	_, err = dao.GetMysql().Insert(userSmsCode)
	if err != nil {
		logger.Error("UserService_SendLoginCode_DB2 | err+%v | data=%+v", err, userSmsCode)
		return
	}
	//发送短信服务
	data := url.Values{}
	data.Add("app_id", "rummy")
	data.Add("type", "1") //发送通道 type=1 验证码类（对实时性有要求） 2通知类
	data.Add("phone", phone)
	data.Add("content", fmt.Sprintf("%v is OTP for your account. Please do not share it with anyone.", code))
	res := utils.HttpPostFrom("http://pubgNginx-753998503.ap-south-1.elb.amazonaws.com:6060/v1/send_sms", data)
	logger.Error("UserService_SendLoginCode_DB2 | err+%v | data=%+v", err, string(res))
	return nil
}

/**
设置用户登录
*/
func (us *UserService) SetRedisUserInfo(user *model.User) (err error) {
	dao.RedisLoginSet(fmt.Sprint(user.Id), user.Token)
	return nil
}

//UpdateInfo update userInfo
func (us *UserService) UpdateInfo(ctx context.Context, user *model.User) (err error) {
	if user.Id == 0 {
		return fmt.Errorf("UID_MUST")
	}
	user.NickName = ""
	user.Avatar = ""
	user.FacebookId = ""
	user.GoogleId = ""
	user.Phone = ""
	user.From = ""
	user.DeviceId = ""
	user.Token = ""
	_, err = dao.GetMysql().Context(ctx).Where("id = ?", user.Id).Update(user)
	if err != nil {
		logger.Error("UserService_SUpdateInfo_DB1 | err+%v | data=%+v", err, user)
	}
	return
}
